package org.github.manx98.jlibhac.tools.ncm;

import lombok.Data;
import org.github.manx98.jlibhac.common.math.IByteUtil;
import org.github.manx98.jlibhac.common.math.Uint32;
import org.github.manx98.jlibhac.common.math.Uint64;
import org.github.manx98.jlibhac.common.reflect.StructureMap;
import org.github.manx98.jlibhac.fs.IStorage;
import org.github.manx98.jlibhac.tools.fssystem.ncautils.TitleVersion;

import java.io.IOException;

/**
 * @author Manx98
 * @version 1.0
 * @since 2022/10/6 18:11
 */
@Data
public class Cnmt {
    private byte[] Hash;
    private CnmtContentEntry[] ContentEntries;
    private CnmtContentMetaEntry[] MetaEntries;
    private CnmtExtended ExtendedData;
    private TitleVersion MinimumApplicationVersion;
    private TitleVersion MinimumSystemVersion;
    private Uint64 PatchTitleId;
    private Uint64 ApplicationTitleId;
    public Uint64 TitleId;
    public TitleVersion TitleVersion;
    public ContentMetaType Type;
    public byte FieldD;
    public int TableOffset;
    public int ContentEntryCount;
    public int MetaEntryCount;

    public Cnmt(IStorage reader) throws IOException {
        TitleId = reader.readUint64();
        Uint32 version = reader.readUint32();
        Type = ContentMetaType.valueOf(reader.readByte());
        TitleVersion = new TitleVersion(version, Type.value < ContentMetaType.Application.value);
        FieldD = reader.readByte();
        TableOffset = reader.readUint16().intValue();
        ContentEntryCount = reader.readUint16().intValue();
        MetaEntryCount = reader.readUint16().intValue();

        // Old, pre-release cnmt files don't have the "required system version" field.
        // Try to detect this by reading the padding after that field.
        // The old format usually contains hashes there.
        reader.readBytes(8);
        int padding = reader.readInt();
        boolean isOldCnmtFormat = padding != 0;

        switch (Type) {
            case Application:
                ApplicationTitleId = TitleId;
                PatchTitleId = reader.readUint64();
                MinimumSystemVersion = new TitleVersion(reader.readUint32(), true);
                break;
            case Patch:
                ApplicationTitleId = reader.readUint64();
                MinimumSystemVersion = new TitleVersion(reader.readUint32(), true);
                break;
            case AddOnContent:
                ApplicationTitleId = reader.readUint64();
                MinimumApplicationVersion = new TitleVersion(reader.readUint32(), false);
                break;
        }

        int baseOffset = isOldCnmtFormat ? 0x18 : 0x20;
        reader.setPosition(baseOffset + TableOffset);

        ContentEntries = new CnmtContentEntry[ContentEntryCount];
        MetaEntries = new CnmtContentMetaEntry[MetaEntryCount];

        for (int i = 0; i < ContentEntryCount; i++) {
            ContentEntries[i] = new CnmtContentEntry(reader);
        }

        for (int i = 0; i < MetaEntryCount; i++) {
            MetaEntries[i] = new CnmtContentMetaEntry(reader);
        }

        if (Type == ContentMetaType.Patch) {
            ExtendedData = new CnmtExtended(reader);
        }

        Hash = reader.readBytes(0x20);
    }
}
